
package Controleur;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import Domaine.Noeud;
import Domaine.Reseau;
import Domaine.Segment;
import Domaine.Urgence;
import Domaine.VehiculeUrgence;
import Erreurs.ChiffreInvalide;
import Erreurs.DateInvalide;
import Erreurs.ObjetExistantError;
import Erreurs.ObjetInexistantError;
import GUI.FenetrePrincipale;
import Simulateur.AttenteSurPlace;
import Simulateur.RetourPortAttache;
import Simulateur.Simulation;
import Simulateur.Simulation.EtatSimulation;
import Simulateur.UrgencePlusAncienne;
import Simulateur.UrgencePlusProche;

import javax.swing.Timer;
import javax.swing.event.EventListenerList;

/**
 * 
 * @author Noyau
 * @version 1.0
 * @File Coordonnee.java
 * @since 2013-11-13
 *
 */

//enum ModeEdition { AJOUT_NOEUD, AJOUT_SEGMENT, NONE };

public class GestionnaireSimulateur  implements Cloneable
{
	/*
	 * 
	 * Attributs
	 * 
	 */
	
	public enum ModeEdition { AJOUT_NOEUD, AJOUT_SEGMENT, NONE, DEL_SEGMENT,MOVE_NOEUD,MOVE_SEGMENT,RAPID_EDIT };
	private final EventListenerList listeners = new EventListenerList();
	private Reseau reseau;
	//private Reseau reseauCopy;
	
	private Simulation _simulation;
	
	private Timer _simulationTimer;
	private ModeEdition mode = ModeEdition.NONE;
	
	//sauvegarder info pr�c�dente
	private boolean _simulationEnCours;
	
	
	/*
	 * 
	 * M�thodes
	 * 
	 */
	public GestionnaireSimulateur() 
	{
		this.reseau = new Reseau();
		_simulation = new Simulation(reseau);
	}
	
	public GestionnaireSimulateur clone() 
	{
		GestionnaireSimulateur copy = null;
		try
		{
			copy = (GestionnaireSimulateur) super.clone();
		} catch(CloneNotSupportedException copyExcept)
		{
			copyExcept.printStackTrace(System.err);
		}
	
		copy.reseau = reseau.clone();
		copy._simulation = new Simulation(copy.reseau);
		
		return copy;
	}
	
	public void modifierStrategieAttente(int bouton)
	{
		if (bouton == 1)
		{
			_simulation.setStrategieAttente(new RetourPortAttache(reseau));
		}
		else
		{
			_simulation.setStrategieAttente(new AttenteSurPlace(reseau));
		}
	}
	
	public void modifierStrategie(int bouton)
	{
		if (bouton == 1)
		{
			_simulation.setStrategie(new UrgencePlusProche(reseau));
		}
		else
		{
			_simulation.setStrategie(new UrgencePlusAncienne(reseau));
		}
	}
	
	public void ajouterNoeud(int x, int y){
		Noeud nouvNoeud = new Noeud(new Point(x,y));
		try
		{
			this.reseau.ajoutNoeud(nouvNoeud);
		}
		catch(ObjetExistantError e)
		{
			// Ajouter Message d'erreur, ( si necessaire, peut �tre retirer ces exceptions que je pense pas utiles )
		}

	}
	
	public void supprimerNoeud(Noeud n){
		try{
			this.reseau.supprimerNoeud(n);
		}catch(ObjetInexistantError e){
			// TODO ...
		}
	}
	
	public Noeud getNoeud(int x, int y){
		Noeud n = this.reseau.getNoeud(x,  y);
		return n;
	}
	
	public void ajouterSegment(Noeud depart, Noeud arrivee){
		Segment nouvSegment = new Segment(depart, arrivee);
		try
		{
			this.reseau.ajoutSegment(nouvSegment);
		} catch(ObjetExistantError e) {
			// Message d'erreur.
		}
		
	}
	
	public void supprimerSegment(Segment s){
		
		try{
			this.reseau.supprimerSegment(s);
		}catch(ObjetInexistantError e){
			// TODO ...
		}
	}
	
	public Noeud getNodeByCoordinate(int x, int y){
		
		Noeud n = this.reseau.getNoeud(x, y);
		return n;
	}
	
	// Fonction calculant si il existe un noeud � la position donn�e.
	public boolean exists(Point p){
		
		boolean b = false;
		if(this.getNodeByCoordinate( (int) p.getX(), (int) p.getY()) != null){
			b = true;
		}
		
		return b;
	}
	
	public boolean exists(Segment s){
		
		return this.reseau.exists(s);
	}
	
	public ArrayList<Segment> getSuccesseurs(Noeud n){
		
		return this.reseau.getSuccesseurs(n);
		
	}
	
	public Reseau getReseau() {
		return this.reseau;
	}
	
	public void setReseau(Reseau reseauCopy) {
		this.reseau = reseauCopy;
	}
	
	// M�thode pour le N�cessaire au ModeListener.
	public void addModeListener(ModeListener listener){
		this.listeners.add(ModeListener.class, listener);
	}
	
	public void removeModeListener(ModeListener listener){
		this.listeners.remove(ModeListener.class, listener);
	}
	
	public ModeListener[] getModeListener(){
		return this.listeners.getListeners(ModeListener.class);
	}
	
	protected void fireModeChanged(ModeEdition old, ModeEdition nouv){
		// Fonction qui lance l'event � tous les listeners.
		if(old != nouv){
			for(ModeListener l: this.getModeListener()){
				l.modeChange(old, nouv);
			}
		}
	}
	
	
	// M�thode pour le N�cessaire au ModeListener.
	public void addSimulationListener(SimulationListener listener){
		this.listeners.add(SimulationListener.class, listener);
	}
	
	public void removeSimulationListener(SimulationListener listener){
		this.listeners.remove(SimulationListener.class, listener);
	}
	
	public SimulationListener[] getSimulationListener(){
		return this.listeners.getListeners(SimulationListener.class);
	}
	
	protected void fireSimulationChanged(){
		// Fonction qui lance l'event � tous les listeners.
		for(SimulationListener l: this.getSimulationListener()){
				l.simulationChange();
		}
	}

	public Simulation getSimulation() {
		return _simulation;
	}
	
	
	public void demarrerSimulation() 
	{

			int delay = 100; //milliseconds
			
			if (_simulation.getEtat() == EtatSimulation.EnCours)
				return;
			
			
            ActionListener taskPerformer = new ActionListener() {
                  
                    public void actionPerformed(ActionEvent evt) {
                  
                            _simulation.traiterUrgence(true);
                            fireSimulationChanged();
                            
                            if (_simulation.getEtat() != EtatSimulation.EnCours) {
                                    return;
                            }
                            
                            //_simulation.traiterProchaineUrgence();
                            _simulationTimer.restart();
                            
                    }  
            };
            
            _simulationTimer = new Timer(delay, taskPerformer);
            _simulationEnCours = true;
            _simulationTimer.start();
			
		
		  
	}
	
	public void arreterSimulation() {
		_simulation.setEtat(EtatSimulation.Terminee);
		
		if (_simulationTimer != null)
			_simulationTimer.stop();
		
	}
	
	public void resetSimulation() {
	
			_simulation.setEtat(EtatSimulation.EnAttente);
			

	}
	
	
	public void setMode(ModeEdition m){
		// On lance l'event pour les listeners.
		this.fireModeChanged(this.mode, m);
		this.mode = m;
	}
	
	public ModeEdition getMode(){
		return this.mode;
	}
	
	public void ajouterUrgence(Noeud n, String date, String temps){
		
		
		Date d = null;
		float t = 0f;
		
		//DateFormat format = new SimpleDateFormat("dd/MM/yyyy");
		DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		try{
			t = Float.parseFloat(temps);
		}catch(NumberFormatException e){
			// TODO Error Dialog
			
		}
		
		// Si la date est vide, on ajoute une urgence sans sp�cifier la date ( voir constructeur Urgence )
		if(!(date.isEmpty())){
			
			try{
				d = format.parse(date);
			}catch(ParseException e){
				// TODO ...
			}
			
			// Ajout d'une urgence avec date
			try{
				n.ajouterUrgence(new Urgence(t,d));
			}catch(ObjetExistantError e){

				// TODO ...
			}catch(ChiffreInvalide e){

				// TODO ...
			}catch(DateInvalide e){

				// TODO ...
			}
			
		}else{
			
			try{
				n.ajouterUrgence(new Urgence(t));
			}catch(ObjetExistantError e){
				// TODO ...
			}catch(ChiffreInvalide e){
				// TODO ...
			}
			
		}
		

		fireSimulationChanged();
		
		
	}
}
